package com.bangyu.monitor.core.schedule;

import cn.hutool.core.date.DateUtil;
import com.bangyu.monitor.core.common.constant.Const;
import com.bangyu.monitor.core.util.BendCacuUtil;
import com.bangyu.monitor.core.util.InfluxDbUtil;
import com.bangyu.monitor.modular.system.entity.StandDisplayment;
import com.bangyu.monitor.modular.system.entity.Bridge;
import com.bangyu.monitor.modular.system.entity.StaticStandDisplayment;
import com.bangyu.monitor.modular.system.service.BridgeService;
import com.bangyu.monitor.modular.system.service.OriginalDataService;
import com.bangyu.monitor.modular.system.service.StaticStandDisplaymentService;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.influxdb.dto.QueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.*;

/**
 * @Auther: zhangxue
 * @Date: 19/4/23 12:03
 * @Description: 每天凌晨获取前一天的静态数据得到今天的标准静态挠度值
 */
@Slf4j
@Component
public class StaticDisplaymentSchedule {


    @Autowired
    private BridgeService bridgeService;

    @Autowired
    private StaticStandDisplaymentService staticStandDisplaymentService;

    @Value("${mqtt.receiveData}")
    private boolean receiveData;

    private static ThreadPoolExecutor executor = null;
    private long SIX_HOUR = 1000*60*60*6*Const.MS_NS;
    static {
        executor = new  ThreadPoolExecutor(10, 10,
                1000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        executor.allowCoreThreadTimeOut(true);

    }

    //每天0点执行
    @Scheduled(cron = "1 0 0 * * ?")
    public void task(){
        if(receiveData){
            return;
        }
        try{
            Calendar calendar = Calendar.getInstance();

            String today = DateFormatUtils.format(calendar.getTime(),"yyyy-MM-dd");
            calendar.add(Calendar.DATE,-1);
            //前一天日期
            long startTime = calendar.getTimeInMillis()*Const.MS_NS;
            long endTime = (startTime+SIX_HOUR);//6点之前\

            log.info("计算标准静态挠度开始");
            //获取有设备编号的桥梁
            List<Bridge> bridges = bridgeService.listAll(null);
            if(CollectionUtils.isNotEmpty(bridges)){
                for(Bridge bridge:bridges){
                    String deviceNo = bridge.getDeviceNo();

                    if(StringUtils.isNotBlank(deviceNo)){
                         executor.execute((Runnable) () -> {
                            System.out.println("device_no:"+deviceNo);

                            try{
                                String  sql1 = String.format("select  temperature from %s.%s  where device_no = '%s' and time > %d and time < %d ",
                                        Const.INFLUX_RETENTION_POLICY_ONE_HOUR,Const.INFLUX_TABLE_ORIGINAL_DATA,deviceNo,startTime,endTime);

                                QueryResult queryResult = InfluxDbUtil.query(Const.INFLUX_DATABASE,sql1);/**/
                                QueryResult.Series series = InfluxDbUtil.getSeries(queryResult);
                                if(series != null && CollectionUtils.isNotEmpty(series.getValues())){
                                    Map<Object,Integer> map = Maps.newHashMap();

                                    for(List<Object> list :series.getValues()){
                                        Object temperature = CollectionUtils.isNotEmpty(list)?list.get(1):null;
                                        if(temperature !=null){
                                            if(map.get(temperature) == null){
                                                map.put(temperature,0);
                                            }else {
                                                map.put(temperature,map.get(temperature)+1);
                                            }
                                        }
                                    }
                                    Integer i = 0;
                                    Object maxCountTemperature = null;
                                    for(Object key:map.keySet()){
                                        if(map.get(key) >i){
                                            i = map.get(key);
                                            maxCountTemperature = key;
                                        }
                                    }
                                    if(maxCountTemperature != null){
                                        String  sql2 = String.format("select  mean(v0) from %s.%s  where device_no = '%s' and temperature = %s and time > %d and time < %d ",
                                                Const.INFLUX_RETENTION_POLICY_ONE_HOUR,Const.INFLUX_TABLE_ORIGINAL_DATA,deviceNo,maxCountTemperature,startTime,endTime);
                                        QueryResult queryResult2 = InfluxDbUtil.query(Const.INFLUX_DATABASE,sql2);/**/
                                        QueryResult.Series series2 = InfluxDbUtil.getSeries(queryResult2);
                                        if(series2 != null){
                                            if(CollectionUtils.isNotEmpty(series2.getValues())){
                                                List<Object> v = series2.getValues().get(0);
                                                Object static_stand_Displayment = v.get(1);
                                                if(static_stand_Displayment != null){
                                                    StaticStandDisplayment staticStandDisplayment = cacuDisplaymentOfOtherTemperature(today,bridge,(Double) static_stand_Displayment,(Double) maxCountTemperature);
                                                    staticStandDisplaymentService.insert(staticStandDisplayment);

                                                }
                                            }
                                        }
                                    }
                                }
                            }catch (Exception e){
                                log.error("统计标准静态位移失败,device_no {}",deviceNo,e);
                            }

                        });
                    }


                }

            }


        }catch (Exception e){
            log.info("统计静态位移定时任务出错",e);
        }

    }

    private StaticStandDisplayment cacuDisplaymentOfOtherTemperature(String today,Bridge bridge,Double displayment,Double temperature){
        StaticStandDisplayment staticStandDisplayment = new StaticStandDisplayment();
        staticStandDisplayment.setBridgeId(bridge.getBridgeId());
        staticStandDisplayment.setBeamNo(bridge.getBeamNo());
        staticStandDisplayment.setDeviceNo(bridge.getDeviceNo());
        staticStandDisplayment.setYear(today.substring(0,4));
        staticStandDisplayment.setDate(today.substring(5));


        staticStandDisplayment.setOriginalTemperature(temperature.floatValue());
        staticStandDisplayment.setStaticDisplayment(displayment.floatValue());
        staticStandDisplayment
                .setNegative5(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),-5f));
        staticStandDisplayment
                .setNegative10(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),-10f));
        staticStandDisplayment
                .setNegative15(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),-15f));
        staticStandDisplayment
                .setNegative20(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),-20f));
        staticStandDisplayment
                .setNegative25(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),-25f));
        staticStandDisplayment
                .setPositive5(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),5f));
        staticStandDisplayment
                .setPositive10(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),10f));
        staticStandDisplayment
                .setPositive15(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),15f));
        staticStandDisplayment
                .setPositive20(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),20f));
        staticStandDisplayment
                .setPositive25(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),25f));
        staticStandDisplayment.setZero(cacuTargetDisplayment(displayment.floatValue(),temperature.floatValue(),0f));

        return staticStandDisplayment;

    }

    private Float cacuTargetDisplayment(Float displayment,Float temperature,Float targetTemperature){
        return BendCacuUtil.cacuTargetDisplaymentFromCurrent(temperature,
                displayment,targetTemperature);
    }

}
